/* Copyright (c) 2013 OpenPlans - www.openplans.org. All rights reserved.
 * This code is licensed under the GPL 2.0 license, available at the root
 * application directory.
 */
package org.geoserver.threadlocals;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

import org.geoserver.platform.GeoServerExtensions;

/**
 * Collects all {@link ThreadLocalTransfer} found in the application context and applies them on
 * request. This object is not thread safe, it's meant to be instantiated when a transfer is
 * required To use it:
 * <ul>
 * <li>Create a {@link ThreadLocalsTransfer} in the request thread</li>
 * <li>Pass the object as state to the {@link Runnable}/{@link Callable} being run in a thread pool</li>
 * <li>As the {@link Runnable}/{@link Callable} starts its activity, invoke {@link #apply()}</li>
 * <li>In a finally block wrapping the whole activity of the {@link Runnable}/{@link Callable} call
 * {@link #cleanup()} to clean the current Thread {@link ThreadLocal} variables</li>
 * </ul>
 * 
 * @author Andrea Aime - GeoSolutions
 * 
 */
public class ThreadLocalsTransfer {

    Map<String, Object> storage = new HashMap<String, Object>();

    private List<ThreadLocalTransfer> transfers;

    /**
     * Starts and runs all registered {@link ThreadLocalsTransfer} objects and collects the associated thread
     * locals in the storage object
     */
    public ThreadLocalsTransfer() {
        transfers = GeoServerExtensions.extensions(ThreadLocalTransfer.class);
        for (ThreadLocalTransfer transfer : transfers) {
            transfer.collect(storage);
        }
    }

    /**
     * Set the thread local values in the current thread
     */
    public void apply() {
        for (ThreadLocalTransfer transfer : transfers) {
            transfer.apply(storage);
        }
    }

    /**
     * Clean up the thread locals in the current thread
     */
    public void cleanup() {
        for (ThreadLocalTransfer transfer : transfers) {
            transfer.cleanup();
        }
    }
}
